單元測試(Unit Testing)是針對程式中的某個方法或功能,檢查它是否產生預期結果。

繼續使用原本的 TaskFlow3.Api,還要另外建立一個測試專案。
建立 xUnit 專案dotnet new xunit -n TaskFlow3.Tests -f net10.0
建立專案參考dotnet add .\TaskFlow3.Tests\TaskFlow3.Tests.csproj reference .\TaskFlow3.Api\TaskFlow3.Api.csproj
在 VS Code 左側找到:TaskFlow3.Tests,如果裡面有範本建立的 UnitTest1.cs,可以刪除,避免留下不需要的範例,然後新增:TaskServiceTests.cs
為什麼使用 SQLite 記憶體資料庫
在TaskServiceTests.cs打上程式碼:
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using TaskFlow3.Api.Data;
using TaskFlow3.Api.Services;
using Xunit;
namespace TaskFlow3.Tests
{
public class TaskServiceTests
{
// 測試 1:新增任務
[Fact]
public async Task CreateAsync_ShouldSaveTask()
{
using var connection =
new SqliteConnection("Data Source=:memory:");
await connection.OpenAsync();
var options =
new DbContextOptionsBuilder<TaskFlowDbContext>()
.UseSqlite(connection)
.Options;
using var db = new TaskFlowDbContext(options);
await db.Database.EnsureCreatedAsync();
var service = new TaskService(db);
var task = await service.CreateAsync(
"完成 C# 作業",
"alice-id"
);
Assert.True(task.Id > 0);
Assert.Equal("完成 C# 作業", task.Title);
Assert.Equal("alice-id", task.OwnerIdentityId);
var savedTask = await db.Tasks.FindAsync(task.Id);
Assert.NotNull(savedTask);
}
// 測試 2:使用者只能查看自己的任務
[Fact]
public async Task GetAllAsync_ShouldFilterByOwner()
{
using var connection =
new SqliteConnection("Data Source=:memory:");
await connection.OpenAsync();
var options =
new DbContextOptionsBuilder<TaskFlowDbContext>()
.UseSqlite(connection)
.Options;
using var db = new TaskFlowDbContext(options);
await db.Database.EnsureCreatedAsync();
var service = new TaskService(db);
await service.CreateAsync("Alice 的作業", "alice-id");
await service.CreateAsync("Bob 的作業", "bob-id");
var aliceTasks =
await service.GetAllAsync("alice-id");
Assert.Single(aliceTasks);
Assert.Equal("Alice 的作業", aliceTasks[0].Title);
Assert.Equal("alice-id", aliceTasks[0].OwnerIdentityId);
}
// 測試 3:不能刪除其他人的任務
[Fact]
public async Task DeleteAsync_ShouldRejectOtherOwner()
{
using var connection =
new SqliteConnection("Data Source=:memory:");
await connection.OpenAsync();
var options =
new DbContextOptionsBuilder<TaskFlowDbContext>()
.UseSqlite(connection)
.Options;
using var db = new TaskFlowDbContext(options);
await db.Database.EnsureCreatedAsync();
var service = new TaskService(db);
var task = await service.CreateAsync(
"Alice 的私人任務",
"alice-id"
);
bool deleted = await service.DeleteAsync(
task.Id,
"bob-id"
);
Assert.False(deleted);
var savedTask = await db.Tasks.FindAsync(task.Id);
Assert.NotNull(savedTask);
}
}
}
到 VS Code 終端機輸入:dotnet test .\TaskFlow3.Tests\TaskFlow3.Tests.csproj